package com.qianxunclub.starter.web.exception;

import com.qianxunclub.common.framework.constant.CommonReturnCode;
import com.qianxunclub.common.framework.response.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartException;

import javax.servlet.ServletException;
import java.util.Collection;
import java.util.List;

/**
 * @author chihiro.zhang
 */
@Slf4j
@ControllerAdvice
public class ExceptionAdviceHandler {

    @ResponseBody
    @ExceptionHandler(value = Throwable.class)
    public Result defaultErrorHandler(Exception e){
        Result result = this.handler(e);
        return result;
    }


    private Result handler(Exception e) {
        Result result = Result.code(CommonReturnCode.EXCEPTION);
        //不支持的http方法
        if (e instanceof HttpRequestMethodNotSupportedException) {
            result = this.httpRequestMethodNotSupportedException(e);
        }
        //参数异常
        else if (e instanceof HttpMessageNotReadableException) {
            result = this.httpMessageNotReadableException(e);
        }
        else if (e instanceof TypeMismatchException || e instanceof MultipartException ||e instanceof ServletException) {
            result = this.parameterException(e);
        }
        else if (e instanceof MethodArgumentNotValidException) {
            result = this.methodArgumentNotValidException(e);
        }
        else if (e instanceof BadSqlGrammarException) {
            result = this.badSqlGrammarException(e);
        }
        else if(e instanceof BindException){
            result = this.bindException((BindException) e);
        }
        log.error(result.getMessage(),e);
        return result;
    }

    /**
     * 不支持的http方法
     * @param e
     * @return
     */
    private Result httpRequestMethodNotSupportedException(Exception e){
        String message = "不支持的http方法";
        return Result.code(CommonReturnCode.EXCEPTION).setMessage(message);
    }

    /**
     * 参数异常
     * @param e
     * @return
     */
    private Result httpMessageNotReadableException(Exception e){
        String message = "please check your request body or parameter type!";
        return Result.code(CommonReturnCode.PARAM_ERROR).setMessage(message);
    }

    private Result parameterException(Exception e){
        String message = "please check your parameter type!";
        return Result.code(CommonReturnCode.PARAM_ERROR).setMessage(message);
    }


    private Result methodArgumentNotValidException(Exception e){
        StringBuffer buffer = new StringBuffer();
        List<ObjectError> list = ((MethodArgumentNotValidException) e).getBindingResult().getAllErrors();
        list.forEach(error -> {
            if (error instanceof FieldError) {
                buffer.append(((FieldError) error).getField()).append(":");
            }
            buffer.append(error.getDefaultMessage()).append(",");
        });
        buffer.append("please check your parameter!");
        return Result.code(CommonReturnCode.PARAM_ERROR).setMessage(buffer.toString());
    }

    private Result bindException(BindException e){
        String message = CommonReturnCode.PARAM_ERROR.message();
        List<ObjectError> objectErrorList = e.getBindingResult().getAllErrors();
        if(!CollectionUtils.isEmpty(objectErrorList)){
            ObjectError objectError = objectErrorList.get(0);
            if(objectError instanceof FieldError){
                FieldError fieldError = (FieldError) objectError;
                message = "[" + fieldError.getField() + "]" + fieldError.getDefaultMessage();
            }
        }
        return Result.code(CommonReturnCode.PARAM_ERROR).setMessage(message);
    }

    private Result badSqlGrammarException(Exception e){
        String message = "please check your parameter or sql!";
        return Result.code(CommonReturnCode.EXCEPTION).setMessage(message);
    }

}
